# XXX decide how to handle when the Cheeseshop is down
# XXX Decide how to handle when an exception case occurs; e.g., release doesn't actually exist
import calendar
import datetime
import logging
import distutils2_version as version
import xmlrpclib
import main
import models


def pypi():
    """Return an xmlrpclib.ServerProxy instance for the Cheeseshop."""
    return xmlrpclib.ServerProxy('http://pypi.python.org/pypi',
                                 use_datetime=True)

def projects():
    """Return a list of all known projects."""
    return pypi().list_packages()

def project_details(name, version):
    """Return the details for a project."""
    return pypi().release_data(name, version)

def releases(name):
    """Return a list of releases for a project.

    As the Cheeseshop typically returns versions in newest to oldest, reverse
    that so that it is in chronological order.

    """
    releases_list = pypi().package_releases(name, True)
    releases_list.reverse()
    return releases_list

def metadata(name, version):
    """Return the metadata for a project's release."""
    return pypi().release_data(name, version)

def project_refresh(name):
    """Figure out all the details necessary for a pre-existing project that is
    being added to the index.

    Returns:
        (newest release, newest release data), [(version, version urls)],
        timestamp

    """
    # Get the list of project releases.
    releases_list = releases(name)
    if not releases_list:
        return None
    # Figure out the newest release.
    releases_list.sort(key=main.normalized_version)
    newest_release = releases_list[-1]
    # Multi-call the newest release's data along with download data for every
    # release.
    timestamp = datetime.datetime.utcnow()
    multicall = xmlrpclib.MultiCall(pypi())
    multicall.release_data(name, newest_release)
    for release_name in releases_list:
        multicall.release_urls(name, release_name)
    timestamp = datetime.datetime.utcnow()
    try:
        results = multicall()
    except Exception, exc:
        logging.debug('Exception raised while refreshing %s; doing it '
                      'manually with less' % name)
        releases_list = releases_list[-5:]
        client = pypi()
        newest_details = client.release_data(name, newest_release)
        urls_results = []
        for version in releases_list:
            urls_results.append(client.release_urls(name, version))
        results_iter = iter(urls_results)
    else:
        results_iter = iter(results)
        newest_details = results_iter.next()
    version_details = zip(releases_list, results_iter)
    return (newest_release, newest_details), version_details, timestamp

def updates():
    """Get updates from the Cheeseshop since the last sync."""
    project_details = models.ProjectDetails.singleton()
    last_sync = project_details.latest_pypi_changes
    since_epoch = calendar.timegm(last_sync.utctimetuple())
    return pypi().changelog(since_epoch)

def batch_request(requesting):
    """Batch request project details.

    The 'requesting' argument is a sequence of three-item tuples made up of the
    name, version, and desired info to be requested.

    """
    multicall = xmlrpclib.MultiCall(pypi())
    for name, version, want in requesting:
        if want == 'data':
            multicall.release_data(name, version)
        if want == 'urls':
            multicall.release_urls(name, version)
    results = multicall()
    return list(iter(results))
